<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>js异步编程之异步任务</title>
  <style>
    div[name=section] {
      position: absolute;
      width: 100px;
      height: 100px;
      left: 0;
      background-color: green;
    }
  </style>
</head>
<body>
  <ul>
    <li>首先明确JS是单线程的，即同一时刻JS只做一项任务</li>
    <li>所谓异步任务，即JS优先完成主线程的任务，而同时将其他任务追加到任务队列中，当主线程执行完毕后开始从任务队列中依次执行</li>
    <li>定时器轮询(setTimeout,setInterval)就是异步任务，等待主线程结束继续执行任务队列中的任务</li>
    <li>脚本依赖加载也是异步任务，必须保证被依赖的脚本优先加载，当前脚本才能正常执行</li>
    <li>对于异步任务(定时器轮询，脚本依赖加载)都存在任务嵌套执行(回调地狱调用)的情况(callback hell)，因此引入Promise</li>
  </ul>
  <div name="section"></div>
  <script>
    // 加载图片
    {
      const loadImg = function (src, resolve, reject) {
        const img = new Image()
        img.src = src
        img.style.width = '100%'
        img.onload = () => resolve(img)
        img.onerror = reject
      }
      loadImg('./bg.jpg', (img) => {
        console.log('图片加载成功！')
        img.style.border = '2px solid red'
        document.body.appendChild(img)
      }, () => {
        console.log('图片加载失败！')
      })
      console.log('开始加载...')
    }
    // 定时器
    {
      const interval = (callback, delay = 100) => {
        const id = setInterval(() => callback(id), delay)
      }
      // 移动元素
      const elem = document.querySelector('[name=section]')
      interval((timerId) => {
        let left = parseInt(window.getComputedStyle(elem).left)
        elem.style.left = left + 10 + 'px'
        if (left >= 200) {
          clearInterval(timerId)
          interval((timerId) => {
            let width = parseInt(window.getComputedStyle(elem).width)
            elem.style.width = width - 10 + 'px'
            if (width <= 20) {
              clearInterval(timerId)
            }
          }, 200)
        }
      })
      console.log('定时器开始运行...')
    }
    // 脚本依赖
    {
      const loadScript = (src, resolve, reject) => {
        const script = document.createElement('script')
        script.src = src
        script.onload = () => resolve(script)
        script.onerror = reject
        document.body.appendChild(script)
      }
      loadScript('./a.js', script => {
        loadScript('./b.js', script => b())
      })
      console.log('脚本开始加载...')
    }
  </script>
</body>
</html>
